package com.ergou.easylive.admin.aspect;

import com.ergou.easylive.admin.annotation.AccessLog;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * 访问日志切面
 * 用于拦截并记录客户端访问信息
 *
 * @author Er-Gou
 * @date 2025-10-04
 */
@Aspect
@Component
@Slf4j
public class AccessLogAspect {

    /**
     * 定义切点：拦截所有Controller包下的方法
     */
    @Pointcut("execution(* com.ergou.easylive.admin.controller..*(..))")
    public void controllerPointcut() {
    }

    /**
     * 定义切点：拦截所有标记了@AccessLog注解的方法
     */
    @Pointcut("@annotation(com.ergou.easylive.admin.annotation.AccessLog)")
    public void accessLogPointcut() {
    }

    /**
     * 环绕通知：记录访问日志
     */
    @Around("controllerPointcut() || accessLogPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        
        // 获取请求信息
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes == null) {
            return joinPoint.proceed();
        }
        
        HttpServletRequest request = attributes.getRequest();
        
        // 获取方法信息
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        String className = joinPoint.getTarget().getClass().getSimpleName();
        String methodName = method.getName();
        
        // 获取客户端信息
        String clientIp = getClientIpAddress(request);
        String userAgent = request.getHeader("User-Agent");
        String requestUrl = request.getRequestURL().toString();
        String requestMethod = request.getMethod();
        String queryString = request.getQueryString();
        
        // 构建完整的请求URL
        String fullUrl = requestUrl;
        if (queryString != null && !queryString.isEmpty()) {
            fullUrl += "?" + queryString;
        }
        
        // 记录请求开始日志
        log.info("=== 客户端访问开始 ===");
        log.info("访问地址: {} {}", requestMethod, fullUrl);
        log.info("客户端IP: {}", clientIp);
        log.info("用户代理: {}", userAgent);
        log.info("控制器: {}.{}", className, methodName);
        
        // 获取@AccessLog注解信息
        AccessLog accessLog = method.getAnnotation(AccessLog.class);
        if (accessLog != null) {
            String description = accessLog.value();
            if (!description.isEmpty()) {
                log.info("操作描述: {}", description);
            }
            
            // 记录请求参数
            if (accessLog.includeArgs()) {
                Object[] args = joinPoint.getArgs();
                if (args != null && args.length > 0) {
                    log.info("请求参数: {}", Arrays.toString(args));
                }
            }
        }
        
        Object result = null;
        try {
            // 执行目标方法
            result = joinPoint.proceed();
            
            // 记录响应信息
            long endTime = System.currentTimeMillis();
            long executionTime = endTime - startTime;
            
            log.info("执行耗时: {}ms", executionTime);
            
            if (accessLog != null && accessLog.includeResult()) {
                log.info("响应结果: {}", result);
            }
            
            log.info("=== 客户端访问结束 ===");
            
        } catch (Exception e) {
            long endTime = System.currentTimeMillis();
            long executionTime = endTime - startTime;
            
            log.error("=== 客户端访问异常 ===");
            log.error("异常信息: {}", e.getMessage());
            log.error("执行耗时: {}ms", executionTime);
            log.error("=== 异常访问结束 ===");
            
            throw e;
        }
        
        return result;
    }

    /**
     * 获取客户端真实IP地址
     */
    private String getClientIpAddress(HttpServletRequest request) {
        String xForwardedFor = request.getHeader("X-Forwarded-For");
        if (xForwardedFor != null && !xForwardedFor.isEmpty() && !"unknown".equalsIgnoreCase(xForwardedFor)) {
            // 多次反向代理后会有多个IP值，第一个IP才是真实IP
            return xForwardedFor.split(",")[0].trim();
        }
        
        String xRealIp = request.getHeader("X-Real-IP");
        if (xRealIp != null && !xRealIp.isEmpty() && !"unknown".equalsIgnoreCase(xRealIp)) {
            return xRealIp;
        }
        
        String proxyClientIp = request.getHeader("Proxy-Client-IP");
        if (proxyClientIp != null && !proxyClientIp.isEmpty() && !"unknown".equalsIgnoreCase(proxyClientIp)) {
            return proxyClientIp;
        }
        
        String wlProxyClientIp = request.getHeader("WL-Proxy-Client-IP");
        if (wlProxyClientIp != null && !wlProxyClientIp.isEmpty() && !"unknown".equalsIgnoreCase(wlProxyClientIp)) {
            return wlProxyClientIp;
        }
        
        String httpClientIp = request.getHeader("HTTP_CLIENT_IP");
        if (httpClientIp != null && !httpClientIp.isEmpty() && !"unknown".equalsIgnoreCase(httpClientIp)) {
            return httpClientIp;
        }
        
        String httpXForwardedFor = request.getHeader("HTTP_X_FORWARDED_FOR");
        if (httpXForwardedFor != null && !httpXForwardedFor.isEmpty() && !"unknown".equalsIgnoreCase(httpXForwardedFor)) {
            return httpXForwardedFor.split(",")[0].trim();
        }
        
        // 如果以上都获取不到，则使用request.getRemoteAddr()
        return request.getRemoteAddr();
    }
}
